package server.util.tickevents;

import adventure.Adventure;
import adventure.AdventureEdit;
import adventure.misc.Combat;
import adventure.misc.CombatImp;
import adventure.placeable.Fightable;
import adventure.placeable.Mobile;
import java.util.ArrayList;
import java.util.Random;
import player.Player;
import player.PlayerManager;
import server.util.Broadcaster;

/**
 *
 * @author Michael Hanns
 *
 */
public class ExecuteCombat implements TickerEvent {

    private Adventure adv;
    private Broadcaster broadcaster;
    private PlayerManager players;
    private Combat combatSystem;
    private Random random;

    public ExecuteCombat(Adventure a) {
        this.broadcaster = ((AdventureEdit) a).getBroadcaster();
        this.players = ((AdventureEdit) a).getPlayerManager();
        this.combatSystem = new CombatImp(broadcaster);
        this.adv = a;
        this.random = new Random();
    }

    @Override
    public void executeEvent() {
        aggroMobsAttack();
        aggroGroupsAttack();
        executeFights();
    }

    private void aggroMobsAttack() {
        for (int x = 0; players.getOnlinePlayerAtIndex(x).getID() > 0; x++) {
            adv.aggroMobsAttack(players.getOnlinePlayerAtIndex(x));
        }
    }

    private void aggroGroupsAttack() {
        adv.aggroGroupsAttack();
    }

    private void executeFights() {
        ArrayList<Fightable> fights = getAllFights();

        for (int x = 0; x < fights.size(); x++) {
            Fightable[] targets = fights.get(x).getLocalTargets();

            if (targets.length > 0) {
                if (fights.get(x).isPlayer()) {
                    if (targets[0].isPlayer()) {
                        combatSystem.fight((Player) fights.get(x), (Player) targets[0]);
                    } else {
                        combatSystem.fight((Player) fights.get(x), (Mobile) targets[0]);
                    }
                } else {
                    if (targets[0].isPlayer()) {
                        combatSystem.fight((Mobile) fights.get(x), (Player) targets[0]);
                    } else {
                        //combatSystem.fight((Mobile) fights.get(x), (Mobile) targets[0]);
                    }
                }
            }

        }
        Player newLineTarget;
        // Broadcast a new line to all players in combat to break up bouts.
        for (int x = 0; x < fights.size(); x++) {
            try {
                System.out.println("Fights " + x + ": " + fights.get(x).getAliveName());
                newLineTarget = (Player) fights.get(x);
                broadcaster.broadcastToPlayer(newLineTarget, "");
            } catch (ClassCastException e) {
                ;
            }
        }
    }

    private ArrayList<Fightable> getAllFights() {
        ArrayList<Fightable> fights = getPlayerFights();
        getPlayerFights();

        // Merge player and mobile fights
        for (int x = 0; x < getMobileFights().size(); x++) {
            if (fights.size() > 0) {
                boolean inserted = false;

                for (int y = 0; y
                        < fights.size() && !inserted; y++) {
                    if (getMobileFights().get(x).getSpeed() > fights.get(y).getSpeed()) {
                        fights.add(y, getMobileFights().get(x));
                        inserted = true;
                    } else if (getMobileFights().get(x).getSpeed() == fights.get(y).getSpeed()
                            && random.nextBoolean()) {
                        fights.add(y, getMobileFights().get(x));
                        inserted = true;
                    }
                }
                if (!inserted) {
                    fights.add(getMobileFights().get(x));
                }
            } else {
                fights.add(getMobileFights().get(x));
            }
        }
        return fights;


    }

    private ArrayList<Fightable> getPlayerFights() {
        ArrayList<Fightable> fights = new ArrayList<Fightable>();

        // Add online players with local targets in order of speed.
        for (int x = 0; x
                < players.onlinePlayers(); x++) {
            if (players.getOnlinePlayerAtIndex(x).getLocalTargets().length > 0) {
                boolean inserted = false;

                for (int y = 0; y < fights.size() & !inserted; y++) {
                    // If speeds are the same, 50/50 chance of attacking first.
                    if (players.getOnlinePlayerAtIndex(x).getSpeed() > fights.get(y).getSpeed()) {
                        fights.add(y, (Fightable) players.getOnlinePlayerAtIndex(x));
                        inserted = true;
                    } else if (players.getOnlinePlayerAtIndex(x).getSpeed() == fights.get(y).getSpeed()
                            && random.nextBoolean()) {
                        fights.add(y, (Fightable) players.getOnlinePlayerAtIndex(x));
                        inserted = true;
                    }
                }
                if (!inserted) {
                    fights.add((Fightable) players.getOnlinePlayerAtIndex(x));
                }
            }
        }
        return fights;
    }

    private ArrayList<Fightable> getMobileFights() {
        ArrayList<Fightable> fights = new ArrayList<Fightable>();
        //ArrayList<Player> playersAdded = new ArrayList<Player>();
        Player p;
        // Add online players with local targets in order of speed.
        for (int x = 0; players.getOnlinePlayerAtIndex(x).getID() > 0; x++) {
            //boolean alreadyIn = false;
            p = players.getOnlinePlayerAtIndex(x);

            /*for (int y = 0; y < playersAdded.size() & !alreadyIn; y++) {
             if (p.x() == playersAdded.get(y).x()
             && p.y() == playersAdded.get(y).y()
             && p.z() == playersAdded.get(y).z()) {
             alreadyIn = true;
             }
             }*/
            //if (!alreadyIn) {
            for (int y = 0; y < adv.getAggroMobs(p).length; y++) {
                boolean inserted = false;

                Mobile target = adv.getAggroMobs(p)[y];

                for (int z = 0; z < fights.size() & !inserted; z++) {
                    // If speeds are the same, 50/50 chance of attacking first.
                    if (target.getSpeed() > fights.get(z).getSpeed()) {
                        fights.add(z, (Fightable) target);
                        inserted = true;


                    } else if (p.getSpeed() == fights.get(z).getSpeed()
                            && random.nextBoolean()) {
                        fights.add(z, (Fightable) target);
                        inserted = true;
                    }
                }
                if (!inserted) {
                    fights.add((Fightable) target);
                }
            }
            // }
        }
        return fights;
    }
}
